/*
 * DCE400服务系统 -- 后端服务接口 -- 数据访问层 -- 工单数据访问
 * 包括：
 */
package dao

import (
	"errors"
	"gitee.com/baal1990/gitee.com/baal1990/cmd/server_attence/app/entity"
	"gitee.com/baal1990/gitee.com/baal1990/cmd/server_attence/app/global"
	"gitee.com/baal1990/gitee.com/baal1990/pkg/db"
	"gitee.com/baal1990/gitee.com/baal1990/pkg/util"
	"go.uber.org/zap"
	"time"
)

//********************************************
//Func  ：查询数据库：加班列表分页查询。
//Method：startDate 格式 yyyy-mm-dd hh:MM:dd
//Usage ：
//********************************************
func QueryOvertimeList(page, pageSize, overtimeType, status int,
	startDate, endDate string, applicantId, deptId int64) (int64, []*entity.OvertimeInfo, error) {

	offset := (page - 1) * pageSize
	session := db.Session().Table("overtime") //工单
	defer session.Close()

	if pageSize > 0 {
		session.Limit(pageSize, offset)
	}
	if overtimeType > entity.EOvertimeType_Unknow && overtimeType <= entity.EOvertimeType_Other {
		session = session.And("overtime.type=?", overtimeType)
	}
	if status > entity.EOvertimeStatus_Draft && status <= entity.EOvertimeStatus_Pass {
		session = session.And("overtime.status=?", status)
	}
	if startDate != "" {
		dtLayout := "2006-01-02 15:04:05" //严格按照time包要求的格式
		loc := db.TZLocation()            //转换日期的时区
		start, serr := time.ParseInLocation(dtLayout, startDate, loc)
		if serr == nil {
			session = session.And("overtime.start_date >= ?", start.Format("2006-01-02 15:04:05"))
		}
	}
	if endDate != "" {
		dtLayout := "2006-01-02 15:04:05" //严格按照time包要求的格式
		loc := db.TZLocation()            //转换日期的时区
		end, eerr := time.ParseInLocation(dtLayout, endDate, loc)
		if eerr == nil {
			session = session.And("overtime.end_date <= ?", end.Format("2006-01-02 15:04:05"))
		}
	}
	if applicantId > 0 {
		session = session.And("overtime.applicant_id = ?", applicantId)
	}
	if deptId > 0 {
		session = session.And("overtime.dept_id = ?", deptId)
	}

	overtimeList := []*entity.OvertimeInfo{}
	total, err := session.Omit("applicant_name,approver_name,dept_name,duration_day,apply_type,apply_status").
		Cols("overtime.id,applicant_id,overtime.dept_id,reason,approver_id,start_date,"+
			"end_date,duration,overtime.create_at,approve_at,overtime.type,overtime.status,note,"+
			"department2.dept_id,department2.dept_name").
		Join("INNER", "department2", "overtime.dept_id = department2.dept_id").
		FindAndCount(&overtimeList)

	if err != nil {
		global.Log.Error("sql qurey failed: ", zap.Any("error"+
			":", err))
		return 0, nil, err
	}

	employeeMap := GetAllEmployeeMap()
	for _, v := range overtimeList {
		v.ApplyType = ApplicationDetailTypeString(v.Type)
		v.ApplyStatus = ApplicationStatusString(v.Status) //这个请假和加班是通用的
		if employeeMap != nil {
			user, has := employeeMap[v.ApproverId]
			if has {
				v.ApproverName = user.Name
			}
			user, has = employeeMap[v.ApplicantId]
			if has {
				v.ApplicantName = user.Name
			}
		}
	}
	return total, overtimeList, nil
}

//********************************************
//Func  ：查询数据库：指定加班的详情
//Method：GET
//Usage ：
//********************************************
func QueryOvertimeDetail(Id int64) (*entity.Overtime, error) {
	session := db.Session().Table("overtime")
	defer session.Close()

	var overtime entity.Overtime
	has, err := session.Where("id=?", Id).Get(&overtime)
	if err != nil || has == false {
		return nil, err
	}
	return &overtime, nil
}

//提供连表查询更详细的内容
func QueryOvertimeInfo(Id int64) (*entity.OvertimeInfo, error) {
	var overtimeInfo entity.OvertimeInfo

	session := db.Session().Table("overtime")
	defer session.Close()

	has, err := db.Session().Table("overtime").Where("id=?", Id).
		Cols("overtime.id,applicant_id,overtime.dept_id,reason,approver_id,start_date,"+
			"end_date,duration,overtime.create_at,approve_at,overtime.type,overtime.status,note,"+
			"department2.dept_id,department2.dept_name").
		Join("INNER", "department2", "overtime.dept_id = department2.dept_id").
		Get(&overtimeInfo)

	if err != nil || has == false {
		return nil, err
	}

	applicant, err := QueryEmployeeDetail("", overtimeInfo.ApplicantId)
	if err == nil && applicant != nil {
		overtimeInfo.ApplicantName = applicant.Name
	} else {
		global.Log.Info("QueryOvertimeInfo no found applicant: ", zap.Any("ApplicantId:", overtimeInfo.ApplicantId))
	}

	approver, err := QueryEmployeeDetail("", overtimeInfo.ApproverId)
	if err == nil && approver != nil {
		overtimeInfo.ApproverName = approver.Name
	} else {
		global.Log.Info("QueryOvertimeInfo no found approver: ", zap.Any("ApproverId:", overtimeInfo.ApproverId))
	}

	overtimeInfo.ApplyType = OvertimeTypeString(overtimeInfo.Type)
	overtimeInfo.ApplyStatus = OvertimeStatusString(overtimeInfo.Status)

	return &overtimeInfo, nil
}

//********************************************
//Func  ：添加新加班
//Method：POST
//Usage ：
//********************************************
func InsertOvertime(overtime entity.Overtime) (*entity.Overtime, error) {
	var err error

	overtime.CreateAt = time.Now()
	overtime.Status = entity.EOvertimeStatus_Send
	overtime.Id = util.GenSnowflakeInt64()
	global.Log.Info("InsertOvertime: ", zap.Any("overtime:", overtime))

	session := db.Session().Table("overtime")
	defer session.Close()
	err = session.Begin()
	if err != nil {
		return nil, errors.New("db session begin failed.")
	}
	_, err = session.Insert(&overtime) //插入
	if err != nil {
		session.Rollback()
		return nil, err
	}
	err = session.Commit()
	if err != nil {
		return nil, err
	}
	return &overtime, nil
}

//加班类型信息
func OvertimeTypeString(overtimeType int) string {
	if overtimeType == entity.EOvertimeType_Workday {
		return "工作日加班"
	} else if overtimeType == entity.EOvertimeType_Weekend {
		return "周末加班"
	} else if overtimeType == entity.EOvertimeType_OfficialHoliday {
		return "法定假日加班"
	} else { // if overtimeType == entity.EOvertimeType_Other{
		return "其他"
	}
}

//加班状态信息
func OvertimeStatusString(status int) string {
	if status == entity.EOvertimeStatus_Draft {
		return "编辑中"
	} else if status == entity.EOvertimeStatus_Send {
		return "已提交待审批"
	} else if status == entity.EOvertimeStatus_Delete {
		return "申请已删除"
	} else if status == entity.EOvertimeStatus_Recall {
		return "撤销"
	} else if status == entity.EOvertimeStatus_Refuse {
		return "审批拒绝"
	} else if status == entity.EOvertimeStatus_PassAndCancel {
		return "通过后撤销"
	} else if status == entity.EOvertimeStatus_Pass {
		return "审批通过"
	}
	return ""
}

//********************************************
//Func  ：更新加班信息
//Method：POST
//Usage ：修改： 审批人ID、ApproveAt、Status。或者特殊的cols的内容
//********************************************
func UpdateOvertime(overtime entity.Overtime, cols string) error {
	var err error
	if overtime.Id <= 0 {
		return errors.New("overtime id is none")
	}
	session := db.Session().Table("overtime")
	defer session.Close()
	err = session.Begin()
	if err != nil {
		return err
	}

	if cols == "" {
		cols = "approver_id,approve_at,status"
	}
	_, err = session.Where("id=?", overtime.Id).Cols(cols).Update(overtime)
	if err != nil {
		return err
	}
	err = session.Commit()
	return err
}

//********************************************
//Func  ：批量更新加班信息
//Method：POST
//Usage ：修改： 审批人ID、ApproveAt、Status。或者特殊的cols的内容
//********************************************
func UpdateOvertimeBatch(overtimeList []entity.Overtime, cols string) error {
	var err error
	if len(overtimeList) <= 0 {
		return errors.New("overtime id is none")
	}
	session := db.Session().Table("overtime")
	defer session.Close()
	err = session.Begin()
	if err != nil {
		return err
	}

	if cols == "" {
		cols = "approver_id,approve_at,status"
	}
	for _, overtime := range overtimeList {
		_, err = session.Where("id=?", overtime.Id).Cols(cols).Update(overtime)
		if err != nil {
			session.Rollback()
			return err
		}
	}

	err = session.Commit()
	return err
}

//********************************************
//Func  ：删除加班数据
//Method：DELETE
//Usage ：物理删
//********************************************
func DeleteOvertime(overtimeId int64) error {
	if overtimeId <= 0 {
		return errors.New("overtime id is none")
	}

	session := db.Session().Table("overtime")
	defer session.Close()
	session.Begin()

	cnt, err := session.Where("id=?", overtimeId).Delete(&entity.Overtime{})
	if err != nil {
		session.Rollback()
		return err
	}
	if cnt <= 0 {
		session.Rollback()
		return errors.New("remove 0 overtime")
	}
	err = session.Commit()
	return err
}
